/*

    This file is part of Hometree.

    Hometree is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Hometree is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Hometree.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2011,2012 Roman Held

*/

/*===========================================================================*\
**      Include Dateien
\*===========================================================================*/
#include <QtGui>
#include "treeitem.h"
#include "treemodel.h"
#include "htr/htrmonitor.h"

#define NULL_STR QVariant(QVariant::String)

/*===========================================================================*\
**      Implementation of Class <TreeModel>
\*===========================================================================*/
/*!f---------------------------------------------------------------------------
*/
TreeModel::TreeModel(HtrMonitor *monitor, QObject *parent, QWidget *parentWidget)
     : QAbstractItemModel(parent)
{
  mMonitor = monitor;
  connect(mMonitor, SIGNAL(resDetected(const QString &, qint32)),
          this, SLOT(createUrl(const QString &, qint32)));
  connect(mMonitor, SIGNAL(resRemoved(const QString &)),
          this, SLOT(removeUrl(const QString &)));
  connect(mMonitor, SIGNAL(resChanged(const QString &)),
          this, SLOT(urlIsHot(const QString &)));

  mRootItem = NULL;
  initRootItems();
  mAnimationTimer.start(200);
}

/*!f---------------------------------------------------------------------------
*/
TreeModel::~TreeModel()
{
  Q_ASSERT(mRootItem);
  delete mRootItem;
}

/*!f---------------------------------------------------------------------------
*/
int TreeModel::columnCount(const QModelIndex &parent) const
{
  if (parent.isValid())
    return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
  else
    return mRootItem->columnCount();
}

/*!f---------------------------------------------------------------------------
*/
QModelIndex TreeModel::index(const QString &path) const
{
    Q_ASSERT(mRootItem);
    TreeItem *item = mRootItem->childByPath(path);
    if (!item)
        return QModelIndex();
    return createIndex(item->relativeRow(),0,item);
}

/*!f---------------------------------------------------------------------------
*/
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid())
      return QVariant();
  int col = index.column();
  TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
  switch (role) {
    case Qt::DisplayRole:   return item->data(col);
    case Qt::ToolTipRole:   return item->toolTip();
    case Qt::WhatsThisRole: return item->isDir();
    case Qt::UserRole:      return item->path();
    case Qt::ForegroundRole: return col == 0 ? item->textColor():QColor();
    case Qt::DecorationRole: {
      if (col==TreeItem::COL_NAME)
        return item->icon();
    }
  }
  return QVariant();
}

/*!f---------------------------------------------------------------------------
*/
bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid())
        return false;
    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
    switch (role) {
        case Qt::UserRole: item->setState((TreeItem::IconState)value.toInt()); break;
    }
    emit dataChanged(index, index);
    return true;
}

/*!f---------------------------------------------------------------------------
*/
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
      return 0;

  Qt::ItemFlags f = Qt::ItemIsEnabled;
  if (index.data(Qt::WhatsThisRole).toBool()) //isDir==true
      return f|=Qt::ItemIsDropEnabled;

  f |= Qt::ItemIsSelectable;
  return (index.column()==TreeItem::COL_NAME)?(f|=Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled):f;
}

/*!f---------------------------------------------------------------------------
*/
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{
  if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
    switch (section) {
      case 0 : return tr("Ressource");
      case 1 : return tr("Typ");
    }
  }
  return QVariant();
}

/*!f---------------------------------------------------------------------------
*/
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
  TreeItem *parentItem = NULL;

  if (!parent.isValid())
      parentItem = mRootItem;
  else
      parentItem = static_cast<TreeItem*>(parent.internalPointer());

  TreeItem *childItem = parentItem->child(row);
  if (childItem)
      return createIndex(row, column, childItem);
  else
      return QModelIndex();
}

/*!f---------------------------------------------------------------------------
*/
QStringList TreeModel::mimeTypes() const
{
    return QStringList();
}

/*!f---------------------------------------------------------------------------
*/
QMimeData *TreeModel::mimeData(const QModelIndexList &indexes) const
{
    QMimeData *mimeData = new QMimeData();
    /*
    QByteArray encodedData;
    QDataStream stream(&encodedData, QIODevice::WriteOnly);
    TreeItem::Type itemType = TreeItem::Invalid;
    foreach (const QModelIndex &index, indexes) {
        if (index.isValid()) {
            TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
            item->serialize(&stream);
            itemType = item->type();
            break; // Nur 1 Item!
        }
    }
    QString mimetype = "Something_Wrong-No!One_Knows....(hopefully)";
    switch (itemType) {
        case TreeItem::DbFpgItem:
        case TreeItem::LuaItem: mimetype        = LUA_MIME_TYPE;            break;
        case TreeItem::FpgItem: mimetype        = FPG_MIME_TYPE;            break;
        case TreeItem::FptItem: mimetype        = FPT_MIME_TYPE;            break;
        case TreeItem::DatasetItem: mimetype    = FPG_DS_MIME_TYPE;         break;
        default: qWarning() << "No MimeType for itemType:" << itemType;     break;
    }
    mimeData->setData(mimetype, encodedData);
    */
    return mimeData;
}

/*!f---------------------------------------------------------------------------
*/
bool TreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int , int , const QModelIndex &parent)
{
    return false;
}

/*!f---------------------------------------------------------------------------
*/
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
  if (!index.isValid())
    return QModelIndex();

  TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
  TreeItem *parentItem = childItem->parent();

  if (parentItem == mRootItem)
    return QModelIndex();

  return createIndex(parentItem->relativeRow(), 0, parentItem);
}

/*!f---------------------------------------------------------------------------
*/
int TreeModel::rowCount(const QModelIndex &parent) const
{
  TreeItem *parentItem;

  if (!parent.isValid())
    parentItem = mRootItem;
  else
    parentItem = static_cast<TreeItem*>(parent.internalPointer());

  return parentItem->childCount();
}

/*!f---------------------------------------------------------------------------
*/
const TreeItem *TreeModel::itemAt(const QModelIndex &index) const
{
  TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
  return item; 
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::reset()
{
    beginResetModel();
    if (mRootItem)
        delete mRootItem;
    mRootItem = NULL;
    initRootItems();
    endResetModel();
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::deleteItem(const QModelIndex &index)
{
    if (!index.isValid())
        return;
    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
    if (!item)
        return;
    if (item->isDir())
        return;
    item->deleteAction();
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::createUrl(const QString &url, qint32 resType)
{
  QStringList parts = url.split("/");
  TreeItem *parentItem = mRootItem;
  while (parts.count()) {
    QString nextItemName = parts.takeFirst();
    TreeItem *item = parentItem->childByName(nextItemName);
    if (!item) {
      item = new TreeItem(nextItemName,parentItem);
      connect(&mAnimationTimer, SIGNAL(timeout()),
              item, SLOT(animate()));
      connect(item, SIGNAL(changed(TreeItem*)),
              this, SLOT(itemChanged(TreeItem*)));
      parentItem->appendChild(item);
    }
    parentItem = item;
  }
  parentItem->setResource(url,resType);
  parentItem->setType(TreeItem::ResourceItem);
  emit layoutChanged();
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::removeUrl(const QString &url)
{
  QList<TreeItem*> items = itemsByPath(url);
  for (int i=items.count()-1; i > 0; i--) {
    if (items[i]->childCount() == 0) {
      items[i]->selfDestroy();
    }
  }
  emit layoutChanged();
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::urlIsHot(const QString &url)
{
  QList<TreeItem*> items = itemsByPath(url);
  foreach(TreeItem *item, items)
    item->touch();
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::itemChanged(TreeItem *item)
{
  QModelIndex itemIndex = createIndex(item->relativeRow(),0,item);
  emit dataChanged(itemIndex,itemIndex);
}

/*!f---------------------------------------------------------------------------
*/
void TreeModel::initRootItems()
{
  TreeItem::TreeItemData data;
  data.name = "Root";
  mRootItem = new TreeItem(data, this);
}

/*!f---------------------------------------------------------------------------
*/
QList<TreeItem*> TreeModel::itemsByPath(const QString &path)
{
  QList<TreeItem*> ret;

  QStringList parts = path.split("/");
  TreeItem *parentItem = mRootItem;
  while (parts.count()) {
    QString nextItemName = parts.takeFirst();
    TreeItem *item = parentItem->childByName(nextItemName);
    if (!item) { // Path existiert nicht..
      ret.clear();
      break;
    }
    ret << item;
    parentItem = item;
  }
  return ret;
}

